﻿namespace GoodAdmin.System;

public class SysOrgService : DbRepository<SysOrg>, ISysOrgService, ITransient
{
    private readonly IRedisCacheManager _redisManager;

    public SysOrgService(IRedisCacheManager redisManager)
    {
        _redisManager = redisManager;
    }
    /// <inheritdoc/>
    public async Task AddOrg(OrgAddInput input)
    {
        await CheckInput(input,CommonConst.ACTION_INSERT);
        var parentOrg = await GetOrgDetail(input.ParentId);
        input.CompanyId = parentOrg.CompanyId;
        input.LongName = parentOrg != null? $"{parentOrg.LongName}{input.OrgName}" : input.OrgName;
        
        if(await InsertAsync(input))
        {
            RemoveOrgCache();
            //新增组织时，只会影响上级
            await RemoveDataScopeCache(input.ParentId);
        }        
    }
   
    /// <inheritdoc/>
    public async Task<List<OrgBatchAddOutput>> BatchAddOrg(List<OrgBatchAdd> importData)
    {
        var (orgList, errorList) = await CheckImportData(importData);
        if (orgList.Count > 0)
        {
            var res = await Context.Ado.UseTranAsync(async () =>
            {
                await DbContext.Db.Fastest<SysOrg>().PageSize(100000).BulkCopyAsync(orgList);
            });
            //如果插入失败，那么数据存到errorList，并返回给前端
            if (!res.IsSuccess)
            {
                foreach (var item in orgList)
                {
                    var errorItem = item.Adapt<OrgBatchAddOutput>();
                    errorItem.ErrorMessages = "插入数据库失败";
                    errorList.Add(errorItem);
                }
            }
            else
            {
                //清除组织缓存
                RemoveOrgCache();
                //清除用户缓存
                await RemoveDataScopeCache(orgList);
            }
        }
        return errorList;
        
    }
    /// <inheritdoc/>
    public async Task DeleteOrg(BaseIdInput input)
    {
        //包含下级组织不能删除
        if (await IsAnyAsync(o => o.ParentId == input.Id))
        {
            throw Oops.Bah(OrgErrorCode.O003);
        }
        //包含用户不能删除
        if (await Context.Queryable<SysUser>().AnyAsync(u => u.OrgId == input.Id))
        {
            throw Oops.Bah(OrgErrorCode.O004);
        }
                
        if(await DeleteAsync(o => o.Id == input.Id))
        {
            RemoveOrgCache();
            await RemoveDataScopeCache(input.Id);
        }
        
    }

    /// <inheritdoc/>
    public async Task<OrgSimpleInfo> GetOrgDetail(long OrgId)
    {
        var orgList = await GetOrgList();
        return orgList.FirstOrDefault(o => o.Id == OrgId);
    }
    /// <inheritdoc/>
    public async Task<List<OrgSimpleInfo>> GetOrgList()
    {
        var key = CacheConst.SysOrg;

        var orgList = _redisManager.Get<List<OrgSimpleInfo>>(key);
        if (orgList == null)
        {
            orgList = await GetListAsync<OrgSimpleInfo>();
            _redisManager.Set(key, orgList);
        }
        return orgList;
    }
    /// <inheritdoc/>
    public async Task<List<OrgSimpleInfo>> GetOrgTree(List<long> dataScope=null)
    {        
        var orgList = await GetOrgList();
        if (dataScope!=null)
        {
            orgList =orgList.Where(it=> dataScope.Contains(it.Id)).OrderBy(it=>it.Id).ToList();
        }
        var simpleOrgList = orgList.Adapt<List<OrgSimpleInfo>>();
        return UtilMethod.ConstructTree(simpleOrgList);
    }

    public async Task<List<OrgSimpleInfo>> OrgSelector()
    {
        var orgList = await GetOrgList();
        var simpleOrgList = orgList.Adapt<List<OrgSimpleInfo>>();
        return UtilMethod.ConstructTree(simpleOrgList);
    }
    /// <inheritdoc/>
    public async Task<SqlSugarPagedList<SysOrg>> GetOrgPageList(OrgPageInput input)
    {        
        return await Context.Queryable<SysOrg>()
            .WhereIF(!string.IsNullOrWhiteSpace(input.Category),o=>o.Category==input.Category)
            .WhereIF(input.ParentId>0,o=>o.ParentId==input.ParentId)
            .WhereIF(input.DataScope!=null,o=>input.DataScope.Contains(o.Id))
            .WhereIF(!string.IsNullOrWhiteSpace(input.OrgName),o=>o.OrgName.Contains(input.OrgName))
            .OrderByIF(!string.IsNullOrWhiteSpace(input.SortField),o=> $"{input.SortField} {input.SortOrder}")
            .OrderBy(o=>o.SortCode)
            .ToPagedListAsync(input.PageIndex, input.PageSize);
    }

    /// <inheritdoc/>
    public async Task UpdateOrg(OrgUpdateInput input)
    {
        await CheckInput(input, CommonConst.ACTION_UPDATE);
        var sysOrg = await GetOrgDetail(input.Id);  
        //不能修改组织类型
        if(sysOrg.Category!= input.Category)
        {
            throw Oops.Bah(OrgErrorCode.O011);
        }
        var parentOrg = await GetOrgDetail(input.ParentId);
        //如果修改后的上级部门所属公司与现在部门所属公司不同
        if (parentOrg.CompanyId != sysOrg.CompanyId)
        {
            throw Oops.Bah(OrgErrorCode.O012);
        }
        input.LongName = parentOrg != null ? $"{parentOrg.LongName}{input.OrgName}" : input.OrgName;
        if (await UpdateAsync(input))
        {
            RemoveOrgCache();
            await RemoveUserCache(input.Id);

            //更新前后上级组织如果有变化，需删除数据范围
            if (input.ParentId != sysOrg.ParentId)
            {
                //删除之前上级部门的
                await RemoveDataScopeCache(sysOrg.ParentId);
                //删除更新后的上级部门的
                await RemoveDataScopeCache(input.ParentId);
            }
        }        
    }

    /// <inheritdoc/>
    public async Task<bool> IsOrgExist(long OrgId) 
    {
        var orgList = await GetOrgList();
        return orgList.Any(o => o.Id == OrgId);
    }

    /// <inheritdoc/>
    public async Task<List<long>> GetOrgChildrenIdList(long OrgId, bool isContainSelf = true)
    {
        var orgList = await GetOrgList();
        var curOrg = orgList.Where(o => o.Id == OrgId).FirstOrDefault();
        List<long> result = new();
        if (curOrg == null) 
            return result;

        Queue<OrgSimpleInfo> queue = new();
        queue.Enqueue(curOrg);
        while (queue.Count > 0)
        {
            var org = queue.Dequeue();
            var childs = orgList.Where(o => o.ParentId == org.Id).ToList();
            childs?.ForEach(o =>
            {
                queue.Enqueue(o);
                result.Add(o.Id);
            });
        }
        if (isContainSelf)
        {
            result.Add(OrgId);
        }
        return result;
    }
   
    public async Task<List<long>> GetOrgChildrenIdList(List<long> OrgIdList, bool isContainSelf = true)
    {
        var orgList = await GetOrgList();
        HashSet<long> result = [];
        foreach (var orgId in OrgIdList)
        {
            GetOrgChildrenIdsRecursive(orgId, orgList, result);
        }
        if (isContainSelf)
        {
            result.UnionWith(OrgIdList);
        }
        return [.. result];
    }
    /// <inheritdoc/>
    public async Task<List<long>> GetOrgParentIdList(long orgId, bool isContainSelf = true)
    {
        var orgList = await GetOrgList();
        var curOrg = orgList.Where(o => o.Id == orgId).FirstOrDefault();
        List<long> result = new();
        if (curOrg == null) 
            return result;

        Queue<OrgSimpleInfo> queue = new();
        queue.Enqueue(curOrg);
        while (queue.Count > 0)
        {
            var org = queue.Dequeue();
            var parent= orgList.Where(o => o.Id == org.ParentId).FirstOrDefault();
            if(parent != null) 
            { 
                result.Add(parent.Id);
                queue.Enqueue(parent); 
            }            
        }
        if(isContainSelf)
        {
            result.Add(orgId);
        }
        return result;
    }   

    #region 私有方法
    
    /// <summary>
    /// 检查输入数据是否合法
    /// </summary>
    /// <param name="sysOrg"></param>
    /// <param name="action"></param>
    /// <returns></returns>
    private async Task CheckInput(SysOrg sysOrg,string action)
    {                
        var orgList = await GetOrgList();
        //判断上级组织是否存在,parentId=0表示最上级组织
        if (sysOrg.ParentId>0 && !orgList.Any(o=>o.Id==sysOrg.ParentId))
        {
            throw Oops.Bah(OrgErrorCode.O006);
        }
        //判断同一层级中是否已有同名组织
        if (orgList.Any(o => o.ParentId == sysOrg.ParentId && o.OrgName == sysOrg.OrgName && o.Id != sysOrg.Id))
            throw Oops.Bah(OrgErrorCode.O002);
        //如果组织类型是部门，且没有选择上级部门
        if (sysOrg.Category == CommonConst.ORG_DEPARTMENT && sysOrg.ParentId == 0)
        {
            throw Oops.Bah(OrgErrorCode.O010);
        }
        //修改时需要判断修改后的父级组织是否在自己的下级组织列表里
        if (action== CommonConst.ACTION_UPDATE)
        {
            if (sysOrg.Id == sysOrg.ParentId)
                throw Oops.Bah(OrgErrorCode.O001);
            
            if(!orgList.Any(it=>it.Id== sysOrg.Id))
            {
                throw Oops.Bah(OrgErrorCode.O008);
            }
            var result = new List<long>();
            var child = GetChild(orgList, result, new List<long> { sysOrg.Id});
            if (child.Any(id => id == sysOrg.ParentId))
            {
                throw Oops.Bah(OrgErrorCode.O005);
            }
        }        
    }

    /// <summary>
    /// 构造组织树形列表
    /// </summary>
    /// <param name="orgList"></param>
    /// <param name="ParentId"></param>
    /// <returns></returns>
    private List<SysOrg> ConstructOrgTree(List<SysOrg> orgList, long ParentId)
    {
        var orgs = orgList.Where(it => it.ParentId == ParentId).ToList();
        if (orgs.Count == 0) return orgs;
        foreach (var org in orgs)
        {
            org.Children = ConstructOrgTree(orgList, org.Id);
        }
        return orgs;
    }
    /// <summary>
    /// 使用递归查找下级，不包含自己
    /// </summary>
    /// <param name="result"></param>
    /// <param name="orgIds"></param>
    /// <returns></returns>
    private List<long> GetChild(List<OrgSimpleInfo> orgList, List<long> result, List<long> orgIds)
    {
        if (orgIds.Count == 0) return result;//如果没有下级数据，那么直接返回result结果
        var orgChilds = orgList.Where(o => orgIds.Contains(o.ParentId)).Select(o => o.Id).ToList();
        result.AddRange(orgChilds);
        return GetChild(orgList, result, orgChilds);
    }

    private void GetOrgChildrenIdsRecursive(long orgId, List<OrgSimpleInfo> orgList, HashSet<long> result)
    {
        if (result.Contains(orgId))
            return;
        result.Add(orgId);
        var children = orgList.Where(o => o.ParentId == orgId).ToList();
        children.ForEach(o => GetOrgChildrenIdsRecursive(o.Id, orgList, result));
    }

    /// <summary>
    /// 移除部门信息缓存
    /// </summary>
    private void RemoveOrgCache()
    {
        _redisManager.Remove(CacheConst.SysOrg);
    }

    /// <summary>
    /// 移除当前部门及上级所包含用户的数据范围
    /// </summary>
    /// <param name="orgId"></param>
    /// <returns></returns>
    private async Task RemoveDataScopeCache(long orgId)
    {
        var orgList = new List<long>();
        orgList.AddRange(await GetOrgParentIdList(orgId));
        await RemoveDataScope(orgList);
    }

    /// <summary>
    /// 新增组织之后，可能很多角色的数据范围都会受影响，直接全部清除掉所有用户接口权限缓存
    /// </summary>
    /// <param name="orgIdList"></param>
    /// <returns></returns>
    private async Task RemoveDataScope(List<long> orgIdList)
    {
        if (orgIdList.Count == 0) return;
        var userIdList = await GetFieldListAsync<SysUser, string>(u => orgIdList.Contains(u.Id), 
            u => CacheConst.ApiRole+u.Id.ToString());
        if (userIdList.Count == 0) return;
        _redisManager.Remove(userIdList.ToArray());
    }

    private async Task RemoveDataScopeCache(List<SysOrg> OrgList)
    {
        var orgIdList = OrgList.Select(o => o.Id).ToList();
        //找出当前列表中的最上级
        var topOrgs = OrgList.Where(o => !orgIdList.Contains(o.ParentId)).Select(o=>o.ParentId).ToList();
        List<long> allParentId = new();
        foreach(long id in topOrgs)
        {
            allParentId.AddRange(await GetOrgParentIdList(id));
        }
        await RemoveDataScope(allParentId);
    }

    /// <summary>
    /// 移除当前部门所包含用户信息缓存
    /// </summary>
    /// <param name="orgId"></param>
    /// <returns></returns>
    private async Task RemoveUserCache(long orgId)
    {
        //var userList = await _userService.GetUserByOrgId( orgId);
        var userIdList = await GetFieldListAsync<SysUser, string>(u => u.OrgId == orgId, u => u.Id.ToString());
        if (userIdList.Count > 0)
            _redisManager.HashDel<SysUser>(CacheConst.SysUser, userIdList.ToArray());
    }

    /// <summary>
    /// 检查导入数据
    /// </summary>
    /// <param name="importData"></param>
    /// <returns></returns>
    private async Task<(List<SysOrg>, List<OrgBatchAddOutput>)> CheckImportData(List<OrgBatchAdd> importData)
    {
        List<OrgBatchAddOutput> errorList = new();
        List<SysOrg> orgList = new();
        if (importData.Count == 0)
        {
            return (orgList, errorList);
        }
        
        var sysOrgs = await GetOrgList();
        // 检查导入数据中组织名称是否重复
        var repeatOrgList = importData.GroupBy(it => it.LongName).Where(it => it.Count() > 1).Select(u => u.Key).ToArray();
        //将导入数据按照LongName进行升序排序，以保证上级部门在下级部门之前
        //在扩展服务中已经排序
        //var sortData=importData.OrderBy(x => x.LongName).ToList();
        foreach (var item in importData)
        {
            var errorMessage = string.Empty;
            var res = item.TryValidate();//通过实体验证
            foreach (var error in res.ValidationResults)
            {
                errorMessage += error.ErrorMessage + ";";
            }

            if (sysOrgs.Any(it => it.LongName == item.LongName))
            {
                errorMessage += "当前系统内已包含该组织;";
            }
            if (repeatOrgList.Contains(item.LongName))
            {
                errorMessage += "组织名称重复输入";
            }
            //检查上级部门是否存在
            // 查找最后一个 ">" 的索引
            int lastIndex = item.LongName.LastIndexOf('>');            
            string parentName= lastIndex != -1? item.LongName.Substring(0, lastIndex):"";
            string curOrgName = item.LongName.Substring(lastIndex + 1);
            long parentId = 0,CompanyId=0;
            if (!string.IsNullOrEmpty(parentName))
            {
                //导入的数据中是否有上级组织
                if (importData.Any(it => it.LongName == parentName))
                {
                    if(errorList.Any(it => it.LongName == parentName))
                    {
                        errorMessage += "上级组织导入错误;";
                    }
                    else
                    {
                        var parentOrg = orgList.First(it => it.LongName == parentName);
                        parentId = parentOrg.Id;
                        CompanyId = parentOrg.CompanyId;
                    }                    
                }
                //系统中是否有上级组织
                else if (sysOrgs.Any(it => it.LongName == parentName))
                {
                    var parentOrg = sysOrgs.First(it => it.LongName == parentName);
                    parentId = parentOrg.Id;
                    CompanyId = parentOrg.CompanyId;
                }
                else
                {
                    errorMessage += "上级组织不存在";
                }
            }
            if (!string.IsNullOrEmpty(errorMessage))
            {
                var errorItem = item.Adapt<OrgBatchAddOutput>();
                errorItem.ErrorMessages = errorMessage;
                errorList.Add(errorItem);
            }
            else
            {
                var org = item.Adapt<SysOrg>();
                org.OrgName = curOrgName;
                org.ParentId= parentId;
                //这里手动生成id
                org.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                org.Category = string.IsNullOrWhiteSpace(org.Category) ? CommonConst.ORG_DEPARTMENT : org.Category;
                org.CreateTime = DateTime.Now;
                //如果当前组织类型是公司的话，那么公司Id就是自身Id
                org.CompanyId = org.Category== CommonConst.ORG_COMPANY? org.Id : CompanyId ;
                orgList.Add(org);
            }
        }
        return (orgList, errorList);
    }
    #endregion
}